#pragma once

#include <iostream>
#include <chrono>
#include <thread>
#include <mutex>
#include <shared_mutex>
#include <algorithm>
#include <condition_variable>
#include <future>
#include <functional>
#include <memory>


namespace hello
{

/**
 * 定时任务
 */
class timer
{
public:
    template<typename Rep, typename Period, typename Fn, typename... Args>
    timer(std::chrono::duration<Rep, Period> _dur, Fn&& _func, Args&&... _args) :
        _task(std::bind(_func, _args...)),
        _interval(std::chrono::duration_cast<std::chrono::milliseconds>(_dur)),
        _stop(false)
    {
    }

public:
    ~timer()
    {
        if (_pthread != nullptr && _pthread->joinable()) _pthread->join();
    }

public:
    inline void start()
    {
        _pthread = std::make_shared<std::thread>(&timer::__run, this);
    }

    inline void stop()
    {
        _stop.store(true);
    }

private:
    inline void __run()
    {
        _stop.store(false);
        while (!_stop.load())
        {
            std::unique_lock<std::mutex> _ul(_mt);
            _cv.wait_for(_ul, _interval);
            _task();
        }
    }

private:
    std::shared_ptr<std::thread> _pthread;
    std::function<void()> _task;
    std::chrono::milliseconds _interval;
    std::condition_variable _cv;
    std::mutex _mt;
    std::atomic<bool> _stop;
};

}
